pub use api::*;
pub use r#type::*;
mod api {
  use e_utils::cmd::ExeType;
  use goblin::{self, elf::Elf, pe::PE, Object};
  use std::{
    borrow::Cow,
    collections::HashMap,
    env, fs,
    path::{Path, PathBuf},
  };

  use crate::fileinfo::find_dll_path;

  use super::{ArchType, Dependency, ExeTypeEx, ImportedFunction, PlatformType};

  pub fn find_path(dll_name: &str) -> Option<std::path::PathBuf> {
    #[cfg(not(any(target_os = "windows", target_os = "linux")))]
    let fullpath = None;
    #[cfg(target_os = "windows")]
    let fullpath = find_dll_path(dll_name);
    #[cfg(target_os = "linux")]
    let fullpath = find_so_path(dll_name);
    fullpath
  }
  /// 所有信息
  pub fn all(target: impl AsRef<Path>) -> e_utils::AnyResult<String> {
    Ok(serde_json::to_string(&open(target)?)?)
  }
  /// 寻找完整路径
  pub fn find_so_path(so_name: &str) -> Option<PathBuf> {
    // 1. 检查 LD_LIBRARY_PATH
    if let Ok(ld_library_path) = env::var("LD_LIBRARY_PATH") {
      for dir in ld_library_path.split(':') {
        let path = Path::new(dir).join(so_name);
        if path.exists() {
          return Some(path);
        }
      }
    }

    // 2. 检查 /etc/ld.so.cache
    // 注意：这需要 root 权限，所以我们跳过这一步

    // 3. 检查默认路径 /lib 和 /usr/lib
    for dir in ["/lib", "/usr/lib"] {
      let path = Path::new(dir).join(so_name);
      if path.exists() {
        return Some(path);
      }
    }

    // 4. 检查 /etc/ld.so.conf 中列出的目录
    if let Ok(contents) = fs::read_to_string("/etc/ld.so.conf") {
      for line in contents.lines() {
        if line.starts_with('/') {
          let path = Path::new(line).join(so_name);
          if path.exists() {
            return Some(path);
          }
        }
      }
    }

    None
  }

  pub fn lib_copy(target: impl AsRef<Path>, to: impl AsRef<Path>) -> e_utils::AnyResult<usize> {
    let mut count = 0;
    let to = to.as_ref();
    for lib in lib_data_parse(&fs::read(target)?)? {
      if let Some(p) = lib.fullpath {
        println!("{} -> {}", p.display(), to.display());
        let pto = to.join(p.file_name().unwrap_or_default());
        e_utils::fs::auto_copy(p, &pto)?;
        count += 1;
      }
    }
    Ok(count)
  }
  pub fn open(target: impl AsRef<Path>) -> e_utils::AnyResult<super::Type> {
    let t = target.as_ref();
    let mut res = data_parse(&fs::read(t)?)?;
    // 提取文件名
    res.fname = t.file_name().and_then(|n| n.to_str()).unwrap_or_default().to_string();
    // 提取当前工作目录
    res.cwd = t.parent().and_then(|p| p.to_str().map(|x| x.to_string()));
    res.exe_type = ExeType::from_target(target);
    Ok(res)
  }
  pub async fn a_open(target: impl AsRef<Path>) -> e_utils::AnyResult<super::Type> {
    let t = target.as_ref();
    let mut res = data_parse(&tokio::fs::read(t).await?)?;
    // 提取文件名
    res.fname = t.file_name().and_then(|n| n.to_str()).unwrap_or_default().to_string();
    // 提取当前工作目录
    res.cwd = t.parent().and_then(|p| p.to_str().map(|x| x.to_string()));
    res.exe_type = ExeType::from_target(target);
    Ok(res)
  }
  pub fn lib_data_parse(buffer: &Vec<u8>) -> e_utils::AnyResult<Vec<Dependency>> {
    Ok(match Object::parse(&buffer)? {
      Object::Elf(elf) => elf_lib_data_parse(elf),
      Object::PE(pe) => pe_lib_data_parse(pe),
      _ => return Err("Cannot parse lib data".into()),
    })
  }
  pub fn data_parse(buffer: &Vec<u8>) -> Result<super::Type, goblin::error::Error> {
    let mut slf = super::Type::default();
    match Object::parse(&buffer)? {
      Object::Elf(elf) => {
        slf.platform = PlatformType::Linux;
        slf.architecture = ArchType::from_elf(elf.header.e_machine);
        // 检查是否为 Android ELF
        let is_android = elf.libraries.iter().any(|lib| lib.to_lowercase().contains("android"));
        if is_android {
          slf.platform = PlatformType::Android;
          slf.exe_type = ExeTypeEx::from_android(elf.header.e_type, elf.is_lib).0;
        } else {
          slf.platform = PlatformType::Linux;
          slf.exe_type = ExeTypeEx::from_linux(elf.header.e_type, elf.is_lib).0;
        }
        slf.is_64 = elf.is_64;
        slf.is_lib = elf.is_lib;
        // 添加 ELF 依赖分析
        slf.libs = elf_lib_data_parse(elf);
      }
      Object::PE(pe) => {
        slf.platform = PlatformType::Windows;
        slf.architecture = ArchType::from_pe(pe.header.coff_header.machine);
        slf.exe_type = if pe.is_lib { ExeType::Dll } else { ExeType::WindowsExe };
        slf.is_64 = pe.is_64;
        slf.is_lib = pe.is_lib;
        slf.libs = pe_lib_data_parse(pe);
      }
      Object::Mach(mach) => {
        // Mach-O 可能是 macOS 或 iOS
        match mach {
          goblin::mach::Mach::Binary(macho) => {
            slf.architecture = ArchType::from_mach(macho.header.cputype());
            slf.platform = match slf.architecture {
              ArchType::ARM64_32 | ArchType::ARM | ArchType::ARM64 => PlatformType::IOS,
              _ => PlatformType::MacOS,
            };
            slf.exe_type = ExeType::MacOSApp;
            slf.is_64 = macho.is_64;
          }
          goblin::mach::Mach::Fat(fat) => {
            for arch in fat.iter_arches() {
              if let Ok(arch) = arch {
                let t = ArchType::from_mach(arch.cputype());
                if t != ArchType::Unknown {
                  slf.architecture = t;
                  slf.is_64 = arch.is_64();
                  break;
                }
              }
            }
            slf.platform = PlatformType::MacOS; // Assume Fat binary is macOS
            slf.exe_type = ExeType::MacOSApp;
          }
        }
      }
      Object::COFF(coff) => {
        slf.platform = PlatformType::Windows;
        slf.architecture = ArchType::from_pe(coff.header.machine);
        slf.exe_type = ExeType::Unknown; // COFF files can be various types, we need more info to determine
      }
      Object::Archive(archive) => {
        // Try to determine Archive type and architecture
        if let Some(first_member) = archive.members().get(0) {
          if let Ok(inner_object) = Object::parse(first_member.as_bytes()) {
            match inner_object {
              Object::Elf(_) => {
                slf.platform = PlatformType::Linux;
                slf.exe_type = ExeType::So;
              }
              Object::PE(_) | Object::COFF(_) => {
                slf.platform = PlatformType::Windows;
                slf.exe_type = ExeType::Dll;
              }
              Object::Mach(_) => {
                slf.platform = PlatformType::MacOS;
                slf.exe_type = ExeType::Dll;
              }
              _ => {
                slf.platform = PlatformType::Unknown;
                slf.exe_type = ExeType::Unknown;
              }
            }
            // Try to determine architecture from the first member
            slf.architecture = match inner_object {
              Object::Elf(elf) => ArchType::from_elf(elf.header.e_machine),
              Object::PE(pe) => ArchType::from_pe(pe.header.coff_header.machine),
              Object::Mach(mach) => {
                if let goblin::mach::Mach::Binary(macho) = mach {
                  ArchType::from_mach(macho.header.cputype())
                } else {
                  ArchType::Unknown
                }
              }
              _ => ArchType::Unknown,
            };
          }
        }
        slf.is_lib = true; // Archives are typically libraries
      }
      _ => {}
    }
    Ok(slf)
  }
  fn elf_lib_data_parse(elf: Elf<'_>) -> Vec<Dependency> {
    // 添加 ELF 依赖分析
    let mut libs = HashMap::new();
    for lib in elf.libraries {
      let entry = libs.entry(lib.to_string()).or_insert_with(|| {
        #[cfg(not(any(target_os = "windows", target_os = "linux")))]
        let fullpath = None;
        #[cfg(target_os = "windows")]
        let fullpath = None; // ELF 文件在 Windows 上不适用
        #[cfg(target_os = "linux")]
        let fullpath = super::find::find_so_path(lib);
        Dependency {
          name: lib.to_string(),
          functions: Vec::new(),
          is_exists: fullpath.is_some(),
          fullpath,
        }
      });
      // 分析导入函数
      for sym in elf.dynsyms.iter() {
        if sym.st_type() == goblin::elf::sym::STT_FUNC && sym.st_shndx == 0 {
          if let Some(name) = elf.dynstrtab.get_at(sym.st_name) {
            entry.functions.push(ImportedFunction {
              name: name.to_string(),
              ordinal: 0, // ELF 不使用序数
              rva: sym.st_value as usize,
            });
          }
        }
      }
    }
    libs.into_values().collect()
  }
  fn pe_lib_data_parse(pe: PE<'_>) -> Vec<Dependency> {
    let mut libs = HashMap::new();
    // Detailed dependency analysis for PE
    for import in pe.imports {
      let entry = libs.entry(import.dll.to_string()).or_insert_with(|| {
        #[cfg(not(any(target_os = "windows", target_os = "linux")))]
        let fullpath = None;
        #[cfg(target_os = "windows")]
        let fullpath = find_dll_path(import.dll);
        #[cfg(target_os = "linux")]
        let fullpath = None;
        Dependency {
          name: import.dll.to_string(),
          functions: Vec::new(),
          is_exists: fullpath.is_some(),
          fullpath,
        }
      });

      let function = ImportedFunction {
        name: match import.name {
          Cow::Borrowed(s) => s.to_string(),
          Cow::Owned(s) => s,
        },
        ordinal: import.ordinal,
        rva: import.rva,
      };
      entry.functions.push(function);
    }
    libs.into_values().collect()
  }
}

mod r#type {
  use std::path::PathBuf;

  use e_utils::cmd::ExeType;
  use goblin::elf::header::*;
  use goblin::mach::cputype::*;
  use goblin::pe::header::*;
  use serde::{Deserialize, Serialize};
  use strum::*;

  #[derive(Clone, Debug, Deserialize, Serialize)]
  pub struct Type {
    pub fname: String,
    pub cwd: Option<String>,
    pub exe_type: ExeType,
    pub architecture: ArchType,
    pub platform: PlatformType,
    pub is_lib: bool,
    pub is_64: bool,
    pub libs: Vec<Dependency>,
  }
  impl Default for Type {
    fn default() -> Self {
      Type {
        cwd: Some("#origin#/plugins".to_string()),
        fname: Default::default(),
        exe_type: Default::default(),
        architecture: Default::default(),
        platform: Default::default(),
        is_lib: Default::default(),
        is_64: Default::default(),
        libs: Default::default(),
      }
    }
  }
  #[derive(Default, Clone, Debug, Deserialize, Serialize)]
  pub struct ImportedFunction {
    pub name: String,
    pub ordinal: u16,
    pub rva: usize,
  }

  #[derive(Default, Clone, Debug, Deserialize, Serialize)]
  pub struct Dependency {
    pub name: String,
    pub is_exists: bool,
    pub fullpath: Option<PathBuf>,
    pub functions: Vec<ImportedFunction>,
  }
  /// Operating System Platform
  #[derive(Default, Clone, Copy, Debug, Display, PartialEq, VariantArray, EnumString, Deserialize, Serialize)]
  #[repr(u8)]
  pub enum PlatformType {
    /// Microsoft Windows
    Windows,
    /// Apple macOS
    MacOS,
    /// Linux-based systems
    Linux,
    /// Google Android
    Android,
    /// Apple iOS
    IOS,
    /// Unix-based systems
    Unix,
    ///
    #[default]
    #[strum(to_string = "未知")]
    Unknown,
  }
  impl PlatformType {
    pub fn is_current(&self) -> bool {
      match self {
        PlatformType::Windows => cfg!(target_os = "windows"),
        PlatformType::MacOS => cfg!(target_os = "macos"),
        PlatformType::Linux => cfg!(target_os = "linux"),
        PlatformType::Android => cfg!(target_os = "android"),
        PlatformType::IOS => cfg!(target_os = "ios"),
        PlatformType::Unix => cfg!(unix),
        PlatformType::Unknown => true, // We assume Unknown is compatible with any platform
      }
    }
  }
  /// 可执行文件类型
  #[derive(Debug, Clone)]
  pub struct ExeTypeEx(pub ExeType);
  impl ExeTypeEx {
    pub fn from_linux(t: u16, is_lib: bool) -> Self {
      Self(match t {
        goblin::elf::header::ET_EXEC => ExeType::LinuxExe,
        goblin::elf::header::ET_DYN => {
          if is_lib {
            ExeType::So
          } else {
            ExeType::LinuxExe
          }
        }
        goblin::elf::header::ET_REL => ExeType::Unknown,
        goblin::elf::header::ET_CORE => ExeType::Unknown,
        _ => ExeType::Unknown,
      })
    }
    pub fn from_android(t: u16, is_lib: bool) -> Self {
      Self(match t {
        goblin::elf::header::ET_EXEC => ExeType::AndroidApk,
        goblin::elf::header::ET_DYN => {
          if is_lib {
            ExeType::So
          } else {
            ExeType::AndroidApk
          }
        }
        _ => ExeType::Unknown,
      })
    }
  }
  /// Instruction Set Architecture (ISA)
  #[derive(Default, Clone, Copy, Debug, Display, PartialEq, VariantArray, EnumString, Deserialize, Serialize)]
  #[repr(u8)]
  pub enum ArchType {
    /// x86 architecture (32-bit)
    X86,
    /// x86-64 architecture (64-bit)
    X86_64,
    /// ARM architecture (32-bit)
    ARM,
    /// ARM64 architecture (64-bit)
    ARM64,
    /// MIPS architecture
    MIPS,
    /// PowerPC architecture (32-bit)
    PowerPC,
    /// PowerPC64 architecture (64-bit)
    PowerPC64,
    /// SPARC architecture
    SPARC,
    /// MC68000 architecture
    MC68K,
    /// HP PA-RISC architecture
    HPPA,
    /// MC88000 architecture
    MC88K,
    /// Intel i860 architecture
    I860,
    /// Alpha architecture
    Alpha,
    /// VAX architecture
    VAX,
    /// ARM64_32 architecture
    ARM64_32,
    #[default]
    #[strum(to_string = "未知")]
    Unknown,
  }
  impl ArchType {
    pub fn is_current(&self) -> bool {
      match self {
        ArchType::X86 => cfg!(target_arch = "x86"),
        ArchType::X86_64 => cfg!(target_arch = "x86_64"),
        ArchType::ARM => cfg!(target_arch = "arm"),
        ArchType::ARM64 => cfg!(target_arch = "aarch64"),
        ArchType::MIPS => cfg!(target_arch = "mips"),
        ArchType::PowerPC => cfg!(target_arch = "powerpc"),
        ArchType::PowerPC64 => cfg!(target_arch = "powerpc64"),
        ArchType::SPARC => cfg!(target_arch = "sparc"),
        ArchType::MC68K => cfg!(target_arch = "m68k"),
        ArchType::HPPA => false,
        ArchType::MC88K => false,    // Rust doesn't have a specific target for MC88K
        ArchType::I860 => false,     // Rust doesn't have a specific target for I860
        ArchType::Alpha => false,    // Rust doesn't have a specific target for Alpha
        ArchType::VAX => false,      // Rust doesn't have a specific target for VAX
        ArchType::ARM64_32 => false, // Rust doesn't have a specific target for ARM64_32
        ArchType::Unknown => true,   // We assume Unknown is compatible with any architecture
      }
    }
    pub fn from_mach(value: u32) -> Self {
      match value {
        CPU_TYPE_X86 => ArchType::X86,
        CPU_TYPE_X86_64 => ArchType::X86_64,
        CPU_TYPE_ARM => ArchType::ARM,
        CPU_TYPE_ARM64 => ArchType::ARM64,
        CPU_TYPE_MIPS => ArchType::MIPS,
        CPU_TYPE_POWERPC => ArchType::PowerPC,
        CPU_TYPE_POWERPC64 => ArchType::PowerPC64,
        CPU_TYPE_SPARC => ArchType::SPARC,
        CPU_TYPE_MC680X0 => ArchType::MC68K,
        CPU_TYPE_HPPA => ArchType::HPPA,
        CPU_TYPE_MC88000 => ArchType::MC88K,
        CPU_TYPE_I860 => ArchType::I860,
        CPU_TYPE_ALPHA => ArchType::Alpha,
        CPU_TYPE_VAX => ArchType::VAX,
        CPU_TYPE_ARM64_32 => ArchType::ARM64_32,
        _ => ArchType::Unknown,
      }
    }
    pub fn from_pe(value: u16) -> Self {
      match value {
        COFF_MACHINE_X86 => ArchType::X86,
        COFF_MACHINE_X86_64 => ArchType::X86_64,
        COFF_MACHINE_ARM => ArchType::ARM,
        COFF_MACHINE_ARM64 => ArchType::ARM64,
        COFF_MACHINE_POWERPC => ArchType::PowerPC,
        COFF_MACHINE_ALPHA => ArchType::Alpha,
        _ => ArchType::Unknown,
      }
    }
    pub fn from_elf(value: u16) -> Self {
      match value {
        EM_386 => ArchType::X86,
        EM_X86_64 => ArchType::X86_64,
        EM_ARM => ArchType::ARM,
        EM_AARCH64 => ArchType::ARM64,
        EM_MIPS => ArchType::MIPS,
        EM_PPC => ArchType::PowerPC,
        EM_PPC64 => ArchType::PowerPC64,
        EM_SPARC => ArchType::SPARC,
        _ => ArchType::Unknown,
      }
    }
  }
}
